﻿#include <Sys\RenderUnit\SysRenderDatagram\LIGHTATTRIBRD.HPP>

#define CLightAttrib_ClassID L"072F7118F97C4465A6B1BA03E35B399E"

using namespace CxxlMan;
using namespace Cxxl3D;

cxxlObject *cxxlFASTCALL New_CLightAttribRD();
cxxlPreserve2 *cxxlFASTCALL Regenera_CLightAttribRD(const wchar_t *ClassID);


class CLightAttribRD:public ILightAttribRD
{
  bool m_isModified;


  struct tagAttr 
  {
    char m_bLight:2;    // 是否使用燈光 0:無所謂  1:開  -1:關
    char m_bSpecular:2; // 是否反光光 0:無所謂  1:是  -1:否
    // char m_bAutoNormalize:1; // 是否為 Normalize 做正規化處理 1:是  0:否
    char m_bLocalViewer:1; // 1:計算每個頂點到鏡頭的向量 0:假設頂點就在鏡頭前方，加快速度


    // Color
    union
    {
      struct
      {
        C3D_FLOAT R;
        C3D_FLOAT G;
        C3D_FLOAT B;
        C3D_FLOAT A;
      };
      struct
      {
        C3D_FLOAT m_Color[4];
      };
    };

    
    // Emissive Color
    union
    {
      struct
      {
        C3D_FLOAT EmissiveR;
        C3D_FLOAT EmissiveG;
        C3D_FLOAT EmissiveB;
        C3D_FLOAT EmissiveA;
      };
      struct
      {
        C3D_FLOAT m_EmissiveColor[4];
      };
    };

    // Specular 材質反光銳利度，數值越高越集中於一點
    C3D_FLOAT MaterialShininess;

  }Attr;

  // 比對各屬性，不符就呼叫 ILightAttrib_CEO，由 Render 單元叫用
  virtual void cxxlFASTCALL Chk(const CxxlMan::Smart_Ptr<ILightAttribRD> &ILightAttribRD_Arg, ILightAttrib_CEO *ILightAttrib_CEO_Arg)
  {
    CLightAttribRD *pSrc = (CLightAttribRD *)ILightAttribRD::GetImp(ILightAttribRD_Arg);

    pSrc->csPreserve.Enter();
    tagAttr SrcAttr = pSrc->Attr;
    pSrc->csPreserve.Leave();

    csPreserve.Enter();
    tagAttr ThisAttr = Attr;
    csPreserve.Leave();

    // 燈光
    if(SrcAttr.m_bLight != 0 && SrcAttr.m_bLight != ThisAttr.m_bLight)
      ILightAttrib_CEO_Arg->Light( SrcAttr.m_bLight > 0 );

    // Emissive
    if(SrcAttr.EmissiveR != ThisAttr.EmissiveR || SrcAttr.EmissiveG != ThisAttr.EmissiveG || SrcAttr.EmissiveB != ThisAttr.EmissiveB || SrcAttr.EmissiveA != ThisAttr.EmissiveA)
      ILightAttrib_CEO_Arg->SetEmissive(ThisAttr.m_EmissiveColor);

    // 顏色
    if(SrcAttr.R != ThisAttr.R || SrcAttr.G != ThisAttr.G || SrcAttr.B != ThisAttr.B || SrcAttr.A != ThisAttr.A)
      ILightAttrib_CEO_Arg->SetColor(SrcAttr.m_Color);

    // 反光
    if(SrcAttr.m_bSpecular != 0 && SrcAttr.m_bSpecular != ThisAttr.m_bSpecular)
      ILightAttrib_CEO_Arg->Specular(SrcAttr.m_bSpecular > 0);

    // Specular 材質反光銳利度
    if(SrcAttr.MaterialShininess != ThisAttr.MaterialShininess)
      ILightAttrib_CEO_Arg->SetMaterialShininess(SrcAttr.MaterialShininess);

    // AutoNormalize
    // if(SrcAttr.m_bAutoNormalize != ThisAttr.m_bAutoNormalize)
    //  ILightAttrib_CEO_Arg->AutoNormalize(SrcAttr.m_bAutoNormalize);

    // LocalViewer
    if(SrcAttr.m_bLocalViewer != ThisAttr.m_bLocalViewer)
      ILightAttrib_CEO_Arg->Specular_LocalViewer(SrcAttr.m_bLocalViewer);

  }

  // 由 Render 單元叫用，設定所有屬性
  virtual void cxxlFASTCALL SetAll(ILightAttrib_CEO *ILightAttrib_CEO_Arg)
  {
    csPreserve.Enter();
    tagAttr ThisAttr = Attr;
    csPreserve.Leave();

    // 燈光
    if(ThisAttr.m_bLight != 0)
      ILightAttrib_CEO_Arg->Light( ThisAttr.m_bLight > 0 );

    // AutoNormalize
    // ILightAttrib_CEO_Arg->AutoNormalize(ThisAttr.m_bAutoNormalize);

    // LocalViewer
    ILightAttrib_CEO_Arg->Specular_LocalViewer(ThisAttr.m_bLocalViewer);

    // Emissive
    ILightAttrib_CEO_Arg->SetEmissive(ThisAttr.m_EmissiveColor);

    // 顏色
    ILightAttrib_CEO_Arg->SetColor(ThisAttr.m_Color);

    // 反光
    if(ThisAttr.m_bSpecular != 0)
      ILightAttrib_CEO_Arg->Specular(ThisAttr.m_bSpecular > 0);

    // Specular 材質反光銳利度
    ILightAttrib_CEO_Arg->SetMaterialShininess(ThisAttr.MaterialShininess);

  }

  // 由 Render 單元叫用，並恢復設定為 false
  virtual bool cxxlFASTCALL isModified()
  {
    CriticalSecHandle AutoCSH(csPreserve);

    bool vIsModified = m_isModified;
    m_isModified = false;

    return vIsModified;
  }


private:
  virtual void *cxxlFASTCALL GetImp()
  {
    return this;
  }

  // 是否使用燈光 0:無所謂  1:開  -1:關
  virtual void cxxlFASTCALL Light(char Switch)
  {
    csPreserve.Enter();
    Attr.m_bLight = Switch;
    m_isModified = true;
    csPreserve.Leave();
  }


  // 設定顏色
  void cxxlFASTCALL SetColor(C3D_FLOAT R, C3D_FLOAT G, C3D_FLOAT B, C3D_FLOAT A)
  {
    csPreserve.Enter();
    Attr.R = R;
    Attr.G = G;
    Attr.B = B;
    Attr.A = A;
    m_isModified = true;
    csPreserve.Leave();
  }

  // 設定自體發光的顏色
  virtual void cxxlFASTCALL SetEmissive(C3D_FLOAT R, C3D_FLOAT G, C3D_FLOAT B, C3D_FLOAT A)
  {    
    csPreserve.Enter();
    Attr.EmissiveR = R;
    Attr.EmissiveG = G;
    Attr.EmissiveB = B;
    Attr.EmissiveA = A;
    m_isModified = true;
    csPreserve.Leave();
  }

  // 是否反光
  // Switch = 0:無所謂  1:開  -1:關
  // MaterialShininess = 材質反光銳利度，數值越高越集中於一點
  // LocalViewer = true:計算每個頂點到鏡頭的向量 false:假設頂點就在鏡頭前方，加快速度
  virtual void cxxlFASTCALL Specular(char Switch, C3D_FLOAT MaterialShininess,bool LocalViewer)
  {
    csPreserve.Enter();
    Attr.m_bSpecular = Switch;
    Attr.MaterialShininess = MaterialShininess;
    Attr.m_bLocalViewer = LocalViewer;
    m_isModified = true;
    csPreserve.Leave();
  }

  // 是否為 Normalize 做正規化處理
  // Switch = true:是  false:否
  /*
  virtual void cxxlFASTCALL AutoNormalize(bool Switch)
  {
    csPreserve.Enter();
    Attr.m_bAutoNormalize = Switch;
    m_isModified = true;
    csPreserve.Leave();
  }
  */

  // 複製一份，內容相同
  Smart_Ptr<ILightAttribRD> cxxlFASTCALL Clone()
  {
    Smart_Ptr<ILightAttribRD> NewILightAttribRD_Ptr = ILightAttribRD::Create();
    CLightAttribRD *pNewCLightAttribRD = (CLightAttribRD *)ILightAttribRD::GetImp(NewILightAttribRD_Ptr);

    csPreserve.Enter();
    pNewCLightAttribRD->Attr = Attr;
    csPreserve.Leave();

    return NewILightAttribRD_Ptr;
  }

protected:
  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(Filter *F)
  {
    if(F != NULL && ILightAttribRD::Ref(F))
    {
      if(F->Ref((char *)&Attr,sizeof(Attr),L"LATTR") == false) 
        return false;

      LoadFilter *pLoadFilter = dynamic_cast<LoadFilter*>(F);
      if(pLoadFilter && pLoadFilter->isChk() == false)      
        m_isModified = true;

      return true;
    }
    else
      return false;
  }

public:
  // Constructor
  CLightAttribRD()
    :cxxlObject(CxxlMan::Spirit_Easy),    
    cxxlPreserve2(CLightAttrib_ClassID) // 在建構時指定 ClassID    
  {
    memset(&Attr,0,sizeof(Attr));
    m_isModified = true;
  }
  virtual ~CLightAttribRD()
  {
  }

  friend cxxlObject *cxxlFASTCALL New_CLightAttribRD();
  friend cxxlPreserve2 *cxxlFASTCALL Regenera_CLightAttribRD(const wchar_t *ClassID);

};


cxxlObject *cxxlFASTCALL New_CLightAttribRD()
{
  return new CLightAttribRD();
}

cxxlPreserve2 *cxxlFASTCALL Regenera_CLightAttribRD(const wchar_t *ClassID)
{
  if(wcscmp(CLightAttrib_ClassID, ClassID) == 0)
    return new CLightAttribRD;
  else
    return NULL;

}
